#include "Quad.h"
#include "Vertex.h"

namespace D3D10Shapes
{
	Quad::Quad()
		: mNumRows(0)
		, mNumColumns(0)
		, mNumVertices(0)
		, mNumFaces(0)
		, mDevice(0)
		, mVertexBuffer(0)
		, mIndexBuffer(0)
	{
	
	}

	Quad::~Quad()
	{
		D3D10Utils::ReleaseCOM(mVertexBuffer);
		D3D10Utils::ReleaseCOM(mIndexBuffer);
	}

	void Quad::init(ID3D10Device *device, const unsigned __int32 numRows, const unsigned __int32 numColumns, const float cellSpacing)
	{
		mDevice = device;

		mNumRows = numRows;
		mNumColumns = numColumns;

		mNumVertices = mNumRows * mNumColumns;
		mNumFaces = (mNumRows - 1) * (mNumColumns - 1) * 2;
	
		initVertexBuffer(cellSpacing);
		initIndexBuffer();
	}

	void Quad::draw()
	{
		unsigned __int32 stride = sizeof(D3D10Utils::Vertex);
    	unsigned __int32 offset = 0;
    	mDevice->IASetVertexBuffers(0, 1, &mVertexBuffer, &stride, &offset);
		mDevice->IASetIndexBuffer(mIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
		mDevice->DrawIndexed(mNumFaces * 3, 0, 0);
	}

	void Quad::initVertexBuffer(const float cellSpacing)
	{
		// Create the geometry and fill the vertex buffer. 
		D3D10Utils::Vertex *vertices = new D3D10Utils::Vertex[mNumVertices];
		
		const float halfWidth = (mNumColumns - 1) * cellSpacing * 0.5f;
		const float halfDepth = (mNumRows - 1) * cellSpacing * 0.5f;

		const float du = 1.0f / (mNumColumns - 1);
		const float dv = 1.0f / (mNumRows - 1);
		for(unsigned __int32 i = 0; i < mNumRows; ++i)
		{
			const float z = halfDepth - i * cellSpacing;
			for(unsigned __int32 j = 0; j < mNumColumns; ++j)
			{	
				const float x = -halfWidth + j * cellSpacing;

				const unsigned __int32 vertexIndex = i * mNumColumns + j;
				vertices[vertexIndex].mPosition = D3DXVECTOR3(x, 0.0f, z);
				vertices[vertexIndex].mNormal = D3DXVECTOR3(0.0f, 1.0f, 0.0f);

				// Stretch texture over grid.
				vertices[vertexIndex].mTexCoord.x = j * du;
				vertices[vertexIndex].mTexCoord.y = i * dv;
			}
		}
 
    	D3D10_BUFFER_DESC vertexBufferDesc;
    	vertexBufferDesc.Usage = D3D10_USAGE_IMMUTABLE;
    	vertexBufferDesc.ByteWidth = sizeof(D3D10Utils::Vertex) * mNumVertices;
    	vertexBufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
    	vertexBufferDesc.CPUAccessFlags = 0;
    	vertexBufferDesc.MiscFlags = 0;
    	
		D3D10_SUBRESOURCE_DATA initData;
    	initData.pSysMem = vertices;
    	HRESULT hr = mDevice->CreateBuffer(&vertexBufferDesc, &initData, &mVertexBuffer);
    	D3D10Utils::ErrorHandler(hr);

		delete[] vertices;
	}
	
	void Quad::initIndexBuffer()
	{
		// Create the index buffer. 
		// 3 indices per face
		unsigned __int32 *indices = new unsigned __int32[mNumFaces * 3]; 

		// Iterate over each quad and compute indices.
		int k = 0;
		for(unsigned __int32 i = 0; i < mNumRows - 1; ++i)
		{
			for(unsigned __int32 j = 0; j < mNumColumns - 1; ++j)
			{
				indices[k] = i * mNumColumns + j;
				indices[k + 1] = i * mNumColumns + j + 1;
				indices[k + 2] = (i + 1) * mNumColumns + j;

				indices[k + 3] = (i + 1) * mNumColumns + j;
				indices[k + 4] = i * mNumColumns + j + 1;
				indices[k + 5] = (i + 1) * mNumColumns + j + 1;

				k += 6; // next quad
			}
		}

		D3D10_BUFFER_DESC indexBufferDesc;
    	indexBufferDesc.Usage = D3D10_USAGE_IMMUTABLE;
    	indexBufferDesc.ByteWidth = sizeof(unsigned __int32) * mNumFaces * 3;
    	indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER;
    	indexBufferDesc.CPUAccessFlags = 0;
    	indexBufferDesc.MiscFlags = 0;
    	
    	D3D10_SUBRESOURCE_DATA initData;
    	initData.pSysMem = indices;
    	HRESULT hr = mDevice->CreateBuffer(&indexBufferDesc, &initData, &mIndexBuffer);
    	D3D10Utils::ErrorHandler(hr);

		delete[] indices;
	}
}
